#include "getWeatherData.h"
#include <stdlib.h>
#include <stdbool.h>

weather_node_manager_t *today_weather_manager;
weather_node_manager_t *secondday_weather_manager;
weather_node_manager_t *thirdday_weather_manager;
weather_node_manager_t *forthday_weather_manager;
weather_node_manager_t *fifthday_weather_manager;
weather_node_manager_t *sixthday_weather_manager;
weather_node_manager_t *seventhday_weather_manager;

char day_weather_temp[7][20]={0};
char night_weather_temp[7][20]={0};
char day_weather_state[7][10]={0};

weather_node_manager_t *WeatherDoubleCircleLinkedListManagerNode()
{
    weather_node_manager_t *Pmanager=malloc(sizeof(struct weather_node_manager));
    if(Pmanager==NULL)
    {
        perror("Pmanager alloc the space error!\n");
        return NULL;
    }

    Pmanager->day_num=0;
    Pmanager->head=NULL;
    Pmanager->tail=NULL;

    return Pmanager;
}

weather_node_t *WeatherDoubleCircleLinkedListNewNode(char *hour_str,
                                                        char *weather_str,
                                                        char *temp_str,
                                                        char *wind_direction_str,
                                                        char *wind_power_str)
{
    weather_node_t *newNode=calloc(1,sizeof(struct weather_node));
    if(newNode==NULL)
    {
        perror("newNode alloc the space error!\n");
        return NULL;
    }

    strcpy(newNode->hour_str,hour_str);
    strcpy(newNode->weather_str,weather_str);
    strcpy(newNode->temp_str,temp_str);
    strcpy(newNode->wind_direction_str,wind_direction_str);
    strcpy(newNode->wind_power_str,wind_power_str);

    newNode->next=newNode;
    newNode->prev=newNode;
    
    return newNode;
}

bool WeatherDoubleCircleLinkedListInsert(weather_node_manager_t *Pmanager,char *hour_str,
                                                                            char *weather_str,
                                                                            char *temp_str,
                                                                            char *wind_direction_str,
                                                                            char *wind_power_str)
{
    weather_node_t *newNode=WeatherDoubleCircleLinkedListNewNode(hour_str,weather_str,temp_str,wind_direction_str,wind_power_str);
    if(newNode==NULL)
    {
        perror("newNode create error!\n");
        return false;
    }

    if(Pmanager->day_num==0)
    {
        Pmanager->head=newNode;
        Pmanager->tail=newNode;
        newNode->next=newNode;
        newNode->prev=newNode;
    }
    else
    {
        Pmanager->tail->next=newNode;
        newNode->prev=Pmanager->tail;
        newNode->next=Pmanager->head;
        Pmanager->head->prev=newNode;
        Pmanager->tail=newNode;

    }

    Pmanager->day_num++;
    return true;
}

bool WeatherDoubleCircleLinkedListDelete(weather_node_manager_t *Pmanager,char *hour_str)
{
    if(Pmanager->head==NULL)
    {
        return false;
    }

    weather_node_t *pos=Pmanager->head;
    do
    {
        if(strcmp(hour_str,pos->hour_str)==0)
        {
            break;
        }        
    
        pos=pos->next;
    }while(pos!=Pmanager->head);

    if(strcmp(pos->hour_str,hour_str)!=0)
    {
        return false;
    }

    if(Pmanager->day_num==1)
    {
        Pmanager->head=NULL;
        Pmanager->tail=NULL;
    }
    else if(pos==Pmanager->head)
    {
        Pmanager->head=pos->next;
        Pmanager->tail->next=Pmanager->head;
        Pmanager->head->prev=Pmanager->tail;
    }
    else if(pos==Pmanager->tail)
    {
        Pmanager->tail=pos->prev;
        Pmanager->head->prev=Pmanager->tail;
        Pmanager->tail->next=Pmanager->head;
    }
    else
    {
        pos->prev->next=pos->next;
        pos->next->prev=pos->prev;
    }

    pos->prev=NULL;
    pos->next=NULL;

    free(pos);
    Pmanager->day_num--;

    return true;
}

void WeatherDoubleCircleLinkedListPrint(weather_node_manager_t *Pmanager)
{
    struct weather_node *pos=Pmanager->head;

    do
    {
        printf("%s\t%s\t%s℃\t%s\t%s\n", pos->hour_str, pos->weather_str, pos->temp_str, pos->wind_direction_str, pos->wind_power_str);
        pos=pos->next;
    }while(pos!=Pmanager->head);
}

void init_weather_data_list(void)
{
    today_weather_manager=WeatherDoubleCircleLinkedListManagerNode();
    secondday_weather_manager=WeatherDoubleCircleLinkedListManagerNode();
    thirdday_weather_manager=WeatherDoubleCircleLinkedListManagerNode();
    forthday_weather_manager=WeatherDoubleCircleLinkedListManagerNode();
    fifthday_weather_manager=WeatherDoubleCircleLinkedListManagerNode();
    sixthday_weather_manager=WeatherDoubleCircleLinkedListManagerNode();
    seventhday_weather_manager=WeatherDoubleCircleLinkedListManagerNode();

    // 验证初始化是否成功
    if(today_weather_manager == NULL || secondday_weather_manager == NULL ||
       thirdday_weather_manager == NULL || forthday_weather_manager == NULL ||
       fifthday_weather_manager == NULL || sixthday_weather_manager == NULL ||
       seventhday_weather_manager == NULL) {
        printf("Error: Failed to initialize one or more weather managers\n");
        return;
    }
}


// 初始化SSL接口
int init_SSL(int tcp_fd, SSL **ssl, SSL_CTX **ctx)
{
    int n, ret;

    /* 初始化https的SSL加密协议 */

    // 加载错误字符串资源
    SSL_load_error_strings();

    // 初始化SSL库
    SSL_library_init();

    // 新建SSL会话
    *ctx = SSL_CTX_new(SSLv23_client_method());
    if (*ctx == NULL)
    {
        fprintf(stderr, "init SSL CTX failed:%s\n",
                ERR_reason_error_string(ERR_get_error()));
        return -1;
    }

    // 根据会话新建SSL加密
    *ssl = SSL_new(*ctx);
    if (*ssl == NULL)
    {
        fprintf(stderr, "new SSL with created CTX failed:%s\n",
                ERR_reason_error_string(ERR_get_error()));
        return -1;
    }

    // 绑定文件描述符，tcp_fd是连接完服务器的文件描述符
    ret = SSL_set_fd(*ssl, tcp_fd);
    if (ret == 0)
    {
        fprintf(stderr, "add SSL to tcp socket failed:%s\n",
                ERR_reason_error_string(ERR_get_error()));
        return -1;
    }

    /* 利用SSL加密连接服务器 */
    ret = SSL_connect(*ssl);
    if (ret != 1)
    {
        fprintf(stderr, "SSL connection failed:%s\n",
                ERR_reason_error_string(ERR_get_error()));
        return -1;
    }

    return 0;
}

void destroy_SSL(SSL *ssl, SSL_CTX *ctx)
{
    int n, ret;

    // close ssl tunnel.
    ret = SSL_shutdown(ssl);
    if (ret != 1)
    {
        fprintf(stderr, "SSL shutdown failed:%s\n",
                ERR_reason_error_string(ERR_get_error()));
    }

    // clear ssl resource.
    SSL_free(ssl);
    SSL_CTX_free(ctx);
    ERR_free_strings();
}

// 流程：参数检查-》域名解析-》TCP连接-》SSL加密-》发送HTTP请求-》接收响应-》解析HTTP头
//          -》解析JSON-》提取天气数据-》显示结果-》清理资源
void get_oneday_weather(const char *APPCode, char *request_date, weather_node_manager_t *weather_manager, int count)
{
    // 检查weather_manager是否有效
    if(weather_manager == NULL) {
        printf("Error: weather_manager is NULL\n");
        return;
    }

    // 清空现有数据
    while(weather_manager->head != NULL) {
        WeatherDoubleCircleLinkedListDelete(weather_manager, weather_manager->head->hour_str);
    }

    const char *appcode = APPCode;
    char web_addr[] = "ali-weather.showapi.com";
    // char URL[1024] = "/area-to-weather-date?area=广州&date=20250826&need3HourForeast=1"; //这种方式用不了
    // char URL[1024] = "/area-to-weather-date?area=%E5%B9%BF%E5%B7%9E&date=20250826&need3HourForeast=1";
    char URL[1024]={0};  //去找下官方有没有介绍

    sprintf(URL, "/area-to-weather-date?areaCode=440100&date=%s&need3HourForcast=1", request_date);
    printf("请求URL: %s\n", URL);
    
    struct hostent *hostinfo;
    char server_ip[20];
    int i;
    
    // 域名解析
    hostinfo = gethostbyname(web_addr);
    if(hostinfo == NULL)
    {
        perror("域名解析失败");
        return -1;
    }

    for(i=0; hostinfo->h_addr_list[i] != NULL;i++)
    {
        printf("服务器的IP地址：%s\n", inet_ntoa(*(struct in_addr *)(hostinfo->h_addr_list[i])));
    }
    
    strcpy(server_ip, inet_ntoa(*(struct in_addr *)(hostinfo->h_addr_list[0])));
    printf("准备连接的服务器的IP地址:%s\n", server_ip);
    
    int skt_fd;
    int retval;

    // TCP连接
    skt_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(skt_fd == -1)
    {
        perror("申请ipv4的tcp接口失败");
        return -1;
    }
    
    struct sockaddr_in addrinfo;
    addrinfo.sin_family = AF_INET;
    addrinfo.sin_port = htons(443);
    addrinfo.sin_addr.s_addr = inet_addr(server_ip);
    
    retval = connect(skt_fd, (struct sockaddr *)&addrinfo, sizeof(addrinfo));
    if(retval == -1)
    {
        perror("连接服务器失败");
        return -1;
    }
    
    printf("client:连接服务器成功\n");

    // SSL加密
    SSL *ssl;
    SSL_CTX *ctx;

    retval = init_SSL(skt_fd, &ssl, &ctx);
    if(retval == -1)
    {
        perror("初始化ssl库失败");
        return -1;
    }

    // 发送请求 - 添加Authorization头
    char request_cmd[4096];
    sprintf(request_cmd, "GET %s HTTP/1.1\r\nHost:%s\r\nAuthorization: APPCODE %s\r\n\r\n",  // 去找下官方有没有介绍
            URL, web_addr, appcode);

    retval = SSL_write(ssl, request_cmd, strlen(request_cmd));
    if(retval <= 0)
    {
        perror("发送数据失败");
        return -1;
    }

    printf("发送请求完毕:%s\n", request_cmd);
    
    // 接收应答
    char buffer[4096*5] = {0};
    ssize_t rd_size;
    char *pos;

    printf("开始接受数据\n");

    rd_size = SSL_read(ssl, buffer, sizeof(buffer)-1);
    if(rd_size <= 0)
    {
        perror("接收数据失败");
        return -1;
    }
    buffer[rd_size] = '\0';

    printf("接收到的原始数据:\n%s\n", buffer);

    // 查找JSON开始位置
    char *json_start = NULL;
    pos = strstr(buffer, "\r\n\r\n");
    if(pos != NULL)
    {
        pos += 4; // 跳过空行(必须要)
        printf("找到HTTP头结束位置\n");
        
        // 进一步查找JSON开始
        json_start = strchr(pos, '{');
        if(json_start != NULL)
        {
            printf("找到JSON开始:\n%s\n", json_start);

            // 预处理JSON数据，移除换行符
            char *json_clean = malloc(strlen(json_start) + 1);
            if(json_clean != NULL) 
            {
                char *src = json_start;
                char *dst = json_clean;
                
                while(*src) 
                {
                    // 检查是否是分块大小标记（十六进制数字后跟换行）
                    if(isxdigit(*src)) 
                    {
                        char *hex_end = src;
                        while(isxdigit(*hex_end)) hex_end++;
                        if(*hex_end == '\r' || *hex_end == '\n') 
                        {
                            // 跳过分块大小标记
                            src = hex_end;
                            // 跳过后续的换行符
                            while(*src == '\r' || *src == '\n') src++;
                            continue;
                        }
                    }
                    
                    // 跳过换行符
                    if(*src != '\n' && *src != '\r') {
                        *dst++ = *src;
                    }
                    src++;
                }
                *dst = '\0';
                
                printf("清理后的JSON:\n%s\n", json_clean);
            }
        
            
            // 解析JSON
            cJSON *json = cJSON_Parse(json_clean);  //将字符数据转换成json对象
            if(json == NULL)
            {
                printf("JSON解析失败\n");
                const char *error_ptr = cJSON_GetErrorPtr();  //返回解析中发生错误的大致位置指针
                if(error_ptr != NULL)
                {
                    printf("错误位置: %s\n", error_ptr);
                }
            }
            else
            {
                printf("JSON解析成功\n");
                
                // 检查API响应码
                cJSON *res_code = cJSON_GetObjectItem(json, "showapi_res_code");
                if(res_code != NULL && cJSON_IsNumber(res_code)) //判断cJSON是否是数字类型
                {
                    printf("API响应码: %d\n", res_code->valueint);
                    
                    if(res_code->valueint == 0)
                    {
                        // 获取响应体
                        cJSON *res_body = cJSON_GetObjectItem(json, "showapi_res_body");
                        if(res_body != NULL)
                        {
                            // cJSON *ret_code = cJSON_GetObjectItem(res_body,"ret_code");
                            // if(ret_code!=NULL && cJSON_IsNumber(ret_code)&&ret_code->valueint==0)
                            // {
                                // 获取城市信息
                                cJSON *cityInfo = cJSON_GetObjectItem(res_body, "cityInfo");
                                if(cityInfo != NULL)
                                {
                                    cJSON *cityName = cJSON_GetObjectItem(cityInfo, "c5");
                                    if(cityName != NULL && cJSON_IsString(cityName))
                                    {
                                        printf("\n=== 城市: %s ===\n", cityName->valuestring);
                                    }
                                }
                                
                                // 获取3小时预报数据
                                char fi_buf[10]={0};
                                switch(count)
                                {
                                case 1:
                                    strcpy(fi_buf,"f1");
                                    break;
                                case 2:
                                    strcpy(fi_buf,"f2");
                                    break;
                                case 3:
                                    strcpy(fi_buf,"f3");
                                    break;
                                case 4:
                                    strcpy(fi_buf,"f4");
                                    break;
                                case 5:
                                    strcpy(fi_buf,"f5");
                                    break;
                                case 6:
                                    strcpy(fi_buf,"f6");
                                    break;
                                case 7:
                                    strcpy(fi_buf,"f7");
                                    break;
                                }
                                cJSON *fi = cJSON_GetObjectItem(res_body, fi_buf);
                                if(fi != NULL)
                                {
                                    cJSON *forecastArray = cJSON_GetObjectItem(fi, "3hourForcast");
                                    if(forecastArray != NULL && cJSON_IsArray(forecastArray))
                                    {
                                        printf("\n=== 24小时天气预报 ===\n");
                                        printf("时间\t\t天气\t温度\t风向\t风力\n");
                                        printf("------------------------------------------------\n");
                                        
                                        int arraySize = cJSON_GetArraySize(forecastArray);
                                        for(int i = 0; i < arraySize; i++)
                                        {
                                            // 获取小时
                                            cJSON *hour;
                                            // 获取天气
                                            cJSON *weather;
                                            // 获取温度
                                            cJSON *temperature;
                                            // 获取风向
                                            cJSON *wind_direction;
                                            // 获取风力
                                            cJSON *wind_power;
                                            cJSON *hourData = cJSON_GetArrayItem(forecastArray, i);
                                            if(hourData != NULL)
                                            {
                                                // 获取时间
                                                hour = cJSON_GetObjectItem(hourData, "hour");
                                                // 获取天气
                                                weather = cJSON_GetObjectItem(hourData, "weather");
                                                // 获取温度
                                                temperature = cJSON_GetObjectItem(hourData, "temperature");
                                                // 获取风向
                                                wind_direction = cJSON_GetObjectItem(hourData, "wind_direction");
                                                // 获取风力
                                                wind_power = cJSON_GetObjectItem(hourData, "wind_power");

                                                if(hour && weather && temperature && wind_direction && wind_power &&
                                                cJSON_IsString(hour) && cJSON_IsString(weather) && 
                                                cJSON_IsString(temperature) && cJSON_IsString(wind_direction) && 
                                                cJSON_IsString(wind_power))
                                                {
                                                    printf("%s\t%s\t%s℃\t%s\t%s\n", 
                                                        hour->valuestring, 
                                                        weather->valuestring,
                                                        temperature->valuestring,
                                                        wind_direction->valuestring,
                                                        wind_power->valuestring);

                                                    weather_temp_history[i]=atoi(temperature->valuestring);
                                                    WeatherDoubleCircleLinkedListInsert(weather_manager,hour->valuestring,
                                                                                                        weather->valuestring,
                                                                                                        temperature->valuestring,
                                                                                                        wind_direction->valuestring,
                                                                                                        wind_power->valuestring);
                                                    // weather_node_t *pos = weather_manager->tail;  // 因为新插入的节点总是tail
                                                    // printf("存入链表的天气：%s/%s\n",pos->weather_str, weather->valuestring);

                                                }
                                                else 
                                                {
                                                    if(!hour) printf("  - hour is missing***********\n");
                                                    else if(!cJSON_IsString(hour)) printf("  - hour is not a string***********\n");
                                                    
                                                    if(!weather) printf("  - weather is missing***********\n");
                                                    else if(!cJSON_IsString(weather)) printf("  - weather is not a string***********\n");
                                                    
                                                    if(!temperature) printf("  - temperature is missing***********\n");
                                                    else if(!cJSON_IsString(temperature)) printf("  - temperature is not a string***********\n");
                                                    
                                                    if(!wind_direction) printf("  - wind_direction is missing***********\n");
                                                    else if(!cJSON_IsString(wind_direction)) printf("  - wind_direction is not a stringcJSON *\n");
                                                    else printf("  - wind_direction: %s\n", wind_direction->valuestring);
                                                    
                                                    if(!wind_power) printf("  - wind_power is missing***********\n");
                                                    else if(!cJSON_IsString(wind_power)) printf("  - wind_power is not a string***********\n");
                                                    else printf("  - wind_power: %s\n", wind_power->valuestring);
                                                }
                                            }
                                        }
                                    }
                                    else
                                    {
                                        printf("未找到3小时预报数据\n");
                                        
                                    }
                                    
                                    // 获取白天和夜间温度
                                    cJSON *day_temp = cJSON_GetObjectItem(fi, "day_air_temperature");
                                    cJSON *night_temp = cJSON_GetObjectItem(fi, "night_air_temperature");
                                    if(day_temp && night_temp && cJSON_IsString(day_temp) && cJSON_IsString(night_temp))
                                    {
                                        printf("\n=== 今日温度 ===\n");
                                        printf("白天: %s℃\t夜间: %s℃\n", 
                                            day_temp->valuestring, night_temp->valuestring);

                                        strcpy(day_weather_temp[count-1], day_temp->valuestring);
                                        strcpy(night_weather_temp[count-1], night_temp->valuestring);
                                        printf("更新白天和晚上温度数组...\n");
                                    }
                                    
                                    // 获取白天和夜间天气
                                    cJSON *day_weather = cJSON_GetObjectItem(fi, "day_weather");
                                    cJSON *night_weather = cJSON_GetObjectItem(fi, "night_weather");
                                    if(day_weather && night_weather && cJSON_IsString(day_weather) && cJSON_IsString(night_weather))
                                    {
                                        printf("白天: %s\t夜间: %s\n", 
                                            day_weather->valuestring, night_weather->valuestring);
                                        strcpy(day_weather_state[count-1], day_weather->valuestring);
                                        printf("*************************天气数组：%s\n***************\n",day_weather_state[count-1]);
                                    }
                                }
                            // }
                            // else
                            // {
                            //     // 业务逻辑错误
                            //     cJSON *remark = cJSON_GetObjectItem(res_body, "remark");
                            //     if(remark != NULL && cJSON_IsString(remark))
                            //     {
                            //         printf("API业务错误: %s\n", remark->valuestring);
                            //     }
                            //     else
                            //     {
                            //         printf("未知的业务错误\n");
                            //     }
                            // }
                                                
                            // 获取备注
                            printf("开始获取备注\n");
                            cJSON *remark = cJSON_GetObjectItem(res_body, "remark");
                            if(remark != NULL && cJSON_IsString(remark))
                            {
                                printf("\n备注: %s\n", remark->valuestring);
                            }
                        }
                    }
                    else
                    {
                        // 获取错误信息
                        cJSON *res_error = cJSON_GetObjectItem(json, "showapi_res_error");
                        if(res_error != NULL && cJSON_IsString(res_error))
                        {
                            printf("错误信息: %s\n", res_error->valuestring);
                        }
                    }
                }
                
                cJSON_Delete(json);
                free(json_clean);
            }
        }
        else
        {
            printf("未找到JSON开始符号 {\n");
            printf("头部之后的内容: %s\n", pos);
        }
    }
    else
    {
        printf("未找到HTTP头结束标记\\r\\n\\r\\n\n");
        printf("尝试直接查找JSON开始...\n");
        
        char *json_start = strchr(buffer, '{');
        if(json_start != NULL)
        {
            printf("直接找到JSON: %s\n", json_start);
        }
        else
        {
            printf("整个响应中都没有找到JSON开始符号\n");
        }
    }

    printf("查看当前插入天气节点:%d\n",weather_manager->day_num);

    
    destroy_SSL(ssl, ctx);
    close(skt_fd);

    return 0;
}

